package services

import (
	"registration-booking/app/common/request"
	"registration-booking/app/common/response"
	"registration-booking/app/models"
	"sort"
	"strconv"
	"strings"
	"time"
)

type testService struct {
}

var TestService = new(testService)

func (testService *testService) ComboList() ([]response.Combo, error) {
	combos, err := models.FindTestComboList()
	if err != nil {
		return nil, err
	}
	res := make([]response.Combo, 0)
	for _, combo := range combos {
		_, i, err := models.FindComboProjectList(combo.ID.ID)
		if err != nil {
			return nil, err
		}
		res = append(res, response.Combo{
			TestCombo: combo,
			Count:     int(i),
		})
	}
	return res, nil
}

func (testService *testService) ComboListPage() (*response.PageData, error) {
	combos, err := models.FindTestComboList()
	if err != nil {
		return nil, err
	}
	res := make([]response.Combo, 0)
	for _, combo := range combos {
		_, i, err := models.FindComboProjectList(combo.ID.ID)
		if err != nil {
			return nil, err
		}
		res = append(res, response.Combo{
			TestCombo: combo,
			Count:     int(i),
		})
	}

	return &response.PageData{
		Total:    int64(len(res)),
		PageData: res,
	}, nil
}

func (testService *testService) GetComboById(comboId string) (*response.Combo, error) {
	id, err := strconv.Atoi(comboId)
	if err != nil {
		return nil, err
	}
	combo, err := models.FindTestComboById(uint(id))
	if err != nil {
		return nil, err
	}
	comboProjectIds, i, err := models.FindComboProjectList(combo.ID.ID)
	if err != nil {
		return nil, err
	}
	projectMap := make(map[uint]*response.Project)
	for _, comboProjectId := range comboProjectIds {
		project, err := models.FindTestProjectById(comboProjectId.ProjectId)
		if err != nil {
			return nil, err
		}
		if _, ok := projectMap[project.ParentId]; !ok {
			parent, err := models.FindTestProjectById(project.ParentId)
			if err != nil {
				return nil, err
			}
			projectMap[project.ParentId] = &response.Project{
				TestProject: parent,
				Children:    make([]models.TestProject, 0),
			}
		}
		projectMap[project.ParentId].Children = append(projectMap[project.ParentId].Children, project)
	}
	res := &response.Combo{
		TestCombo: combo,
		Count:     int(i),
	}
	for _, project := range projectMap {
		res.Projects = append(res.Projects, *project)
	}
	sort.SliceStable(res.Projects, func(i, j int) bool {
		return res.Projects[i].ID.ID < res.Projects[j].ID.ID
	})
	return res, nil
}

func (testService *testService) DeleteCombo(comboId string) (bool, error) {
	atoi, err := strconv.Atoi(comboId)
	if err != nil {
		return false, err
	}
	err = models.DeleteTestComboById(atoi)
	if err != nil {
		return false, err
	}
	return true, err
}

func (testService *testService) UpdateComboById(form models.TestCombo) (bool, error) {
	err := form.Update()
	if err != nil {
		return false, err
	}
	return true, nil
}

func (testService *testService) InsertCombo(form models.TestCombo) (bool, error) {
	err := form.Create()
	if err != nil {
		return false, err
	}
	return true, nil
}

func (testService *testService) GetComboTimeList() ([]response.ComboTime, error) {
	today := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 0, 0, 0, time.Local)
	tomorrow := today.AddDate(0, 0, 1)
	dates, err := models.FindTestDateList(tomorrow)
	if err != nil {
		return nil, err
	}
	res := make([]response.ComboTime, 0)
	for _, date := range dates {
		res = append(res, response.ComboTime{
			TestDate: date,
			Time:     date.Date.Format("01/02"),
		})
	}
	return res, nil
}

func (testService *testService) GetComboBooking(form request.TestBooking, userId string) error {
	uid, err := strconv.Atoi(userId)
	if err != nil {
		return err
	}
	testBooking := models.TestBooking{
		UserId:      uint(uid),
		CardId:      form.CardId,
		TestComboId: form.TestComboId,
		TestDateId:  form.TestDateId,
	}
	err = testBooking.Create()
	if err != nil {
		return err
	}

	return nil
}

func (testService *testService) GetComboBookingHistory(userId string) ([]response.ComboBookingHistory, error) {
	uid, err := strconv.Atoi(userId)
	if err != nil {
		return nil, err
	}
	bookingHistory, err := models.FindComboBookingHistory(uint(uid))
	if err != nil {
		return nil, err
	}
	res := make([]response.ComboBookingHistory, 0)
	for _, booking := range bookingHistory {
		history, err := GetBookingHistoryByBookingId(booking.TestComboId, booking.CardId, booking.TestDateId)
		if err != nil {
			return nil, err
		}
		history.TestBooking = booking

		res = append(res, *history)
	}
	return res, nil
}

func (testService *testService) GetComboBookingHistoryAll(page request.Page) (*response.PageData, error) {

	bookingHistory, count, err := models.FindComboBookingHistoryAll(page.PageNo, page.PageSize)
	if err != nil {
		return nil, err
	}
	res := make([]response.ComboBookingHistory, 0)
	for _, booking := range bookingHistory {
		history, err := GetBookingHistoryByBookingId(booking.TestComboId, booking.CardId, booking.TestDateId)
		if err != nil {
			return nil, err
		}
		history.TestBooking = booking

		res = append(res, *history)
	}
	return &response.PageData{
		Total:    count,
		PageData: res,
	}, nil
}

func (testService *testService) GetComboBookingHistoryById(bookingId, userId string) (*response.ComboBookingHistory, error) {
	uid, err := strconv.Atoi(userId)
	if err != nil {
		return nil, err
	}
	bid, err := strconv.Atoi(bookingId)
	if err != nil {
		return nil, err
	}
	bookingHistory, err := models.FindComboBookingHistoryById(uint(bid), uint(uid))
	if err != nil {
		return nil, err
	}
	history, err := GetBookingHistoryByBookingId(bookingHistory.TestComboId, bookingHistory.CardId, bookingHistory.TestDateId)
	history.TestBooking = bookingHistory
	if err != nil {
		return nil, err
	}
	return history, nil
}

func GetBookingHistoryByBookingId(comboId, cardId, testDateId uint) (*response.ComboBookingHistory, error) {
	combo, err := TestService.GetComboById(strconv.Itoa(int(comboId)))
	if err != nil {
		return nil, err
	}

	card, err := models.FindCardById(cardId)
	if err != nil {
		return nil, err
	}

	testDate, err := models.FindTestDateById(testDateId)
	if err != nil {
		return nil, err
	}
	var WeekDayMap = map[string]string{
		"Monday":    "星期一",
		"Tuesday":   "星期二",
		"Wednesday": "星期三",
		"Thursday":  "星期四",
		"Friday":    "星期五",
		"Saturday":  "星期六",
		"Sunday":    "星期日",
	}
	return &response.ComboBookingHistory{
		ComboTime: response.ComboTime{
			TestDate: testDate,
			Time:     testDate.Date.Format("2006-01-02") + " " + WeekDayMap[testDate.Date.Weekday().String()],
		},
		Card:  card,
		Combo: *combo,
	}, nil
}

func (testService *testService) ProjectListPage(form request.Page) (*response.PageData, error) {
	projects, count, err := models.FindProjects(form.PageNo, form.PageSize)
	if err != nil {
		return nil, err
	}
	res := make([]response.ProjectPlus, 0)
	for _, project := range projects {
		id, err := models.FindTestProjectById(project.ParentId)
		if err != nil {
			return nil, err
		}
		res = append(res, response.ProjectPlus{
			TestProject: project,
			ParentName:  id.ProjectName,
		})
	}

	return &response.PageData{
		Total:    count,
		PageData: res,
	}, nil
}

func (testService *testService) ProjectParent() ([]models.TestProject, error) {
	projects, _, err := models.FindParentProjects()
	if err != nil {
		return nil, err
	}

	return projects, nil
}

func (testService *testService) UpdateParentById(project models.TestProject) (bool, error) {
	err := project.Update()
	if err != nil {
		return false, err
	}
	return true, nil
}

func (testService *testService) InsertProject(project models.TestProject) (bool, error) {
	err := project.Create()
	if err != nil {
		return false, err
	}
	return true, nil
}

func (testService *testService) DeleteProject(projectId string) (bool, error) {
	atoi, err := strconv.Atoi(projectId)
	if err != nil {
		return false, err
	}
	err = models.DeleteTestProjectById(atoi)
	if err != nil {
		return false, err
	}
	return true, err
}

func (testService *testService) GetComboDateListPage(form request.Page) (*response.PageData, error) {
	today := time.Date(time.Now().Year(), time.Now().Month(), time.Now().Day(), 0, 0, 0, 0, time.Local)
	tomorrow := today.AddDate(0, 0, 1)
	dates, count, err := models.FindDatesPage(tomorrow, form.PageNo, form.PageSize)
	if err != nil {
		return nil, err
	}
	res := make([]response.ComboTime, 0)
	var WeekDayMap = map[string]string{
		"Monday":    "星期一",
		"Tuesday":   "星期二",
		"Wednesday": "星期三",
		"Thursday":  "星期四",
		"Friday":    "星期五",
		"Saturday":  "星期六",
		"Sunday":    "星期日",
	}
	for _, date := range dates {
		res = append(res, response.ComboTime{
			TestDate: date,
			Time:     date.Date.Format("2006-01-02") + " " + WeekDayMap[date.Date.Weekday().String()],
		})
	}
	return &response.PageData{
		Total:    count,
		PageData: res,
	}, nil
}

func (testService *testService) UpdateDateById(date response.ComboTime) (bool, error) {
	arr := strings.Split(date.Time, " ")
	if len(arr) > 0 {
		parse, err := time.Parse("2006-01-02", arr[0])
		if err != nil {
			return false, err
		}
		date.Date = parse
	}
	err := date.Update()
	if err != nil {
		return false, err
	}
	return true, nil
}

func (testService *testService) InsertTestDate(date response.ComboTimeReq) (bool, error) {
	d := models.TestDate{}
	arr := strings.Split(date.Time, " ")
	if len(arr) > 0 {
		parse, err := time.Parse("2006-01-02", arr[0])
		if err != nil {
			return false, err
		}
		d.Date = parse
	}
	atoi, err := strconv.Atoi(date.Num)
	if err != nil {
		return false, err
	}
	d.Num = atoi
	err = d.Create()
	if err != nil {
		return false, err
	}
	return true, nil
}

func (testService *testService) DeleteDate(dateId string) (bool, error) {
	atoi, err := strconv.Atoi(dateId)
	if err != nil {
		return false, err
	}
	err = models.DeleteTestDateById(atoi)
	if err != nil {
		return false, err
	}
	return true, err
}
